﻿using System;
using System.ComponentModel;
using System.Linq;
using System.Windows.Forms;
using DevExpress.XtraEditors;
using DevExpress.XtraGrid.Views.Base;
using BL;
using Common;
using DAL.Model;
using UI.Helper;

namespace UI.MainFunctions
{
    public partial class frmStockIn : Base.DialogViewBase
    {
        #region Private variables

        private MasterSession _session;
        private StockInController _stockInController;
        private ProductController _productController;
        private BindingList<StockInDetail> _stockInDetails;
        private BindingList<Transfer> _transfers;
        private Customer[] _customers;
        ProductCategory[] _productCategories;
        private StockIn _stockIn;
        private readonly int _stockInId;
        private readonly FormAction _action;

        #endregion

        #region Constructor

        public frmStockIn ()
        {
            InitializeComponent();
        }

        public frmStockIn(FormAction action) :this()
        {
            _action = action;
        }

        public frmStockIn (int stockInId, FormAction action) : this(action)
        {
            _stockInId = stockInId;
        }

        public frmStockIn (MasterSession session) : this()
        {
            _session = session;
        }

        #endregion

        #region Overide methods

        protected override void InitializeBO ()
        {
            base.InitializeBO();

            if(_session == null)
            {
                _session = new MasterSession();
            }

            _stockInController = new StockInController(_session);
            _productController = new ProductController(_session);
        }

        protected override void PopulateStaticData ()
        {
            base.PopulateStaticData();

            LoadCustomers();
            LoadUoms();
            SetDefaultValues();
            LoadPackageTypes();
            LoadProductCat();
        }

        protected override void PopulateData ()
        {
            base.PopulateData();

            _stockIn = _action != FormAction.New
                       // edit/view mode
                           ? _session.StockIns
                                 .FirstOrDefault(t => t.Id == _stockInId)
                       // new
                           : _stockInController.Create();

            _stockInDetails = new BindingList<StockInDetail>(_stockIn.StockInDetails.ToList());
            dgStockIns.DataSource = _stockInDetails;
            gvStockInDetails.BestFitColumns();

            var list = _session.Transfers
                .SelectMany(t => t.StockInsTransfers
                                 .Where(st => st.StockInId == _stockIn.Id)
                                 .Select(sts => sts.Transfer))
                .ToList();

            _transfers = new BindingList<Transfer>(list);
            dgTransfer.DataSource = _transfers;
            gvTransfer.BestFitColumns();

            BindingData();
            switch(_action)
            {
                case FormAction.View:
                    DisableEditor();
                    break;
                case FormAction.New:
                    tabTransfers.Visible = false;
                    break;
            }

            var rowCount = _transfers.Count;
            for (int i = 0; i < rowCount; i++)
            {
                gvTransfer.ExpandMasterRow(i);
            }

            PrecisionHelper.FormatCurencyPrecision(gcNetQuantity,
                                                   gcGrossQuantity,
                                                   gcQuantity,
                                                   gcPackageQuantity,
                                                   gcTotalQuantity,
                                                   gcMassQuantity,
                                                   gcTransferQuantity,
                                                   gcStockOutMassQuantity,
                                                   gcStockOutQuantity);
        }

        protected override void FormatPrecision()
        {
            PrecisionHelper.FormatCurencyPrecision(gcTotalQuantity,
                                                        gcNetQuantity,
                                                        gcGrossQuantity,
                                                        gcQuantity,
                                                        gcPackageQuantity,
                                                        gcMassQuantity,
                                                        gcTransferQuantity,
                                                        gcStockOutMassQuantity,
                                                        gcStockOutQuantity);
        }

        #endregion

        #region Private methods

        private void DisableEditor()
        {
            txtDocumentNo.Properties.ReadOnly = true;
            deStockedDate.Properties.ReadOnly = true;
            txtContactName.Properties.ReadOnly = true;
            lueCustomers.Properties.ReadOnly = true;
            lueMerchants.Properties.ReadOnly = true;
            gvStockInDetails.OptionsBehavior.Editable = false;
            spSave.Enabled = false;
        }

        private void BindingData ()
        {
            txtDocumentNo.DataBindings.Add(new Binding("Text", _stockIn, "DocumentNo",true));
            deStockedDate.DataBindings.Add(new Binding("EditValue", _stockIn, "StockedDate", true));
            lueCustomers.DataBindings.Add(new Binding("EditValue", _stockIn, "CustomerId", true));
            txtContactName.DataBindings.Add(new Binding("Text", _stockIn, "ContactName",true));
            lueMerchants.DataBindings.Add(new Binding("EditValue", _stockIn, "MerchantId",true));
        }

        private void SetDefaultValues()
        {
            deStockedDate.DateTime = DateTime.Now;
        }

        private void LoadUoms()
        {
            var uoms = _session.UnitOfMeasures.ToArray();
            lueUOM.DataSource = uoms;
            luePackageUOM.DataSource = uoms;
        }

        private void LoadCustomers()
        {
            _customers = _session.Customers.ToArray();
            lueCustomers.Properties.DataSource = _customers;
            lueMerchants.Properties.DataSource = _customers;
        }

        private void LoadProductCat()
        {
            _productCategories = _session.ProductCategories.ToArray();
            lueProductCat.DataSource = _productCategories;
        }

        private void LoadPackageTypes()
        {
            var packageTypes = _session.PackageTypes.ToArray();
            luePackageType.DataSource = packageTypes;
        }

        private bool ValidateData()
        {
            var validated = true;

            if (string.IsNullOrEmpty(_stockIn.DocumentNo))
            {
                txtDocumentNo.ErrorText = "Nhập số phiếu.";
                validated = false;
            }
            else
            {
                txtDocumentNo.ErrorText = string.Empty;
            }

            if (!CommonHelper.IsValidDate(_stockIn.StockedDate))
            {
                deStockedDate.ErrorText = "Ngày nhập không hợp lệ.";
                validated = false;
            }
            else
            {
                deStockedDate.ErrorText = string.Empty;
            }

            if ((int)lueCustomers.EditValue == 0)
            {
                lueCustomers.ErrorText ="Chọn khách hàng.";
                validated = false;
            }
            else
            {
                lueCustomers.ErrorText = string.Empty;
            }

            if (txtDocumentNo.ErrorText != string.Empty)
            {
                return validated;
            }
            
            if(!_stockIn.StockInDetails.Any())
            {
                txtDocumentNo.ErrorText = "Nhập chi tiết hàng hóa.";
                validated = false;
            }
            else
            {
                txtDocumentNo.ErrorText = string.Empty;
            }

            var detail = _session.StockIns
                .FirstOrDefault(t => t.Id != _stockIn.Id &&
                                     t.DocumentNo == _stockIn.DocumentNo);
            if (detail != null && _stockIn.Id != detail.Id)
            {
                txtDocumentNo.ErrorText = "Mã phiếu đã tồn tại";
                validated = false;
            }
            else
            {
                txtDocumentNo.ErrorText = string.Empty;
            }

            return validated;
        }

        #endregion
        
        private void gvStockIn_InitNewRow (object sender, DevExpress.XtraGrid.Views.Grid.InitNewRowEventArgs e)
        {
            var stockinDetail = (StockInDetail) gvStockInDetails.GetRow(e.RowHandle);
            if (stockinDetail == null)
            {
                return;
            }
            stockinDetail.StockIn = _stockIn;
            stockinDetail.Product = _productController.Create();
            _stockIn.StockInDetails.Add((stockinDetail));
        }

        private void gvStockIn_KeyDown (object sender, KeyEventArgs e)
        {
            StockInDetail detail;
            var isNewItemRow = gvStockInDetails.IsNewItemRow(gvStockInDetails.FocusedRowHandle);
            switch (e.KeyData)
            {
                case Keys.Escape:
                    if (!isNewItemRow)
                    {
                        return;
                    }
                    detail = (StockInDetail) gvStockInDetails.GetRow(gvStockInDetails.FocusedRowHandle);
                    if (detail == null || detail.Product == null)
                    {
                        return;
                    }
                    _session.Products.Remove(detail.Product);
                    _session.StockInDetails.Remove(detail);
                    break;
                case Keys.F2:
                    if (isNewItemRow)
                    {
                        return;
                    }
                    detail = (StockInDetail) gvStockInDetails.GetRow(gvStockInDetails.FocusedRowHandle);
                    if (detail == null || detail.Product == null)
                    {
                        return;
                    }

                    var newDetail = _stockInController.CreateDetail(_stockIn);
                    newDetail.Product = _productController.Create();
                    newDetail.Product.Code = detail.Product.Code;
                    newDetail.Product.Name = detail.Product.Name;
                    newDetail.Product.ProductCategory = detail.Product.ProductCategory;
                    newDetail.Product.ProductCategoryId = detail.Product.ProductCategoryId;
                    newDetail.UnitOfMeasure = detail.UnitOfMeasure;
                    newDetail.Quantity = detail.Quantity;
                    newDetail.QuantityInPaper = detail.QuantityInPaper;
                    newDetail.GrossQuantity = detail.GrossQuantity;
                    _stockInDetails.Add(newDetail);

                    break;
                case Keys.Delete:
                    if (isNewItemRow)
                    {
                        return;
                    }
                    if (_stockIn.StockInDetails.Count == 1)
                    {
                        return;
                    }

                    if (DialogResult.No == MessageBox.Show("Bạn muốn xóa dòng đang chọn?",
                                                           "Xác nhận",
                                                           MessageBoxButtons.YesNo))
                    {
                        return;
                    }

                    detail = (StockInDetail) gvStockInDetails.GetRow(gvStockInDetails.FocusedRowHandle);
                    _session.StockInDetails.Remove(detail);
                    gvStockInDetails.DeleteRow(gvStockInDetails.FocusedRowHandle);
                    break;
                default:
                    return;
            }
        }

        private void spSave_Click(object sender, EventArgs e)
        {
            if (!ValidateData())
            {
                return;
            }

            _stockInController.PrepareSavingData(_stockIn);
            _session.CommitChanges();
            Close();
        }
        
        private void spCancel_Click(object sender, EventArgs e)
        {
            Close();
        }
        
        private void luePackageType_EditValueChanged(object sender, EventArgs e)
        {
            var stockinDetail = (StockInDetail)gvStockInDetails.GetRow(gvStockInDetails.FocusedRowHandle);
            if (stockinDetail == null)
            {
                return;
            }
            var lookUpEdit = sender as LookUpEdit;
            if (lookUpEdit == null || lookUpEdit.EditValue == null)
            {
                return;
            }
            
            var packageTypes = lookUpEdit.Properties.DataSource as PackageType[];
            stockinDetail.PackageType = packageTypes
                .FirstOrDefault(t => t.Id == (int)lookUpEdit.EditValue);
        }

        private void luePackageUOM_EditValueChanged(object sender, EventArgs e)
        {
            var stockinDetail = (StockInDetail)gvStockInDetails.GetRow(gvStockInDetails.FocusedRowHandle);
            if (stockinDetail == null)
            {
                return;
            }
            var lookUpEdit = sender as LookUpEdit;
            if (lookUpEdit == null || lookUpEdit.EditValue == null)
            {
                return;
            }

            var packageUom= lookUpEdit.Properties.DataSource as UnitOfMeasure[];
            stockinDetail.PackageUom = packageUom
                .FirstOrDefault(t => t.Id == (int)lookUpEdit.EditValue);
        }

        private void lueUOM_EditValueChanged(object sender, EventArgs e)
        {
            var stockinDetail = (StockInDetail)gvStockInDetails.GetRow(gvStockInDetails.FocusedRowHandle);
            if (stockinDetail == null || stockinDetail.PackageUom != null)
            {
                return;
            }
            var lookUpEdit = sender as LookUpEdit;
            if (lookUpEdit == null || lookUpEdit.EditValue == null)
            {
                return;
            }

            var productUom = lookUpEdit.Properties.DataSource as UnitOfMeasure[];
            stockinDetail.UnitOfMeasure = productUom
                .FirstOrDefault(t => t.Id == (int)lookUpEdit.EditValue);
        }

        private void lueCustomers_EditValueChanged(object sender, EventArgs e)
        {
            var customer =_customers
                .FirstOrDefault(t => t.Id == (int)lueCustomers.EditValue);
            if (customer == null)
            {
                return;
            }
            _stockIn.Customer = customer;
            _stockIn.ContactName = customer.ContactName;
        }
        
        private void lueMerchant_EditValueChanged(object sender, EventArgs e)
        {
            if (lueMerchants.EditValue == DBNull.Value)
            {
                return;
            }
            var merchant = _customers
                .FirstOrDefault(t => t.Id == (int) lueMerchants.EditValue);
            _stockIn.Merchant = merchant;
        }

        private void gvTransfer_MasterRowGetChildList(object sender, DevExpress.XtraGrid.Views.Grid.MasterRowGetChildListEventArgs e)
        {
            var row = (Transfer)gvTransfer.GetRow(e.RowHandle);
            e.ChildList = new BindingSource(row, "TransferDetails");
        }

        private void gvTransfer_MasterRowGetRelationCount(object sender, DevExpress.XtraGrid.Views.Grid.MasterRowGetRelationCountEventArgs e)
        {
            e.RelationCount = 1;
        }

        private void gvTransfer_MasterRowGetRelationName(object sender, DevExpress.XtraGrid.Views.Grid.MasterRowGetRelationNameEventArgs e)
        {
            e.RelationName = "TransferDetails";
        }

        private void gvTransfer_MasterRowEmpty(object sender, DevExpress.XtraGrid.Views.Grid.MasterRowEmptyEventArgs e)
        {
            var row = (Transfer)gvTransfer.GetRow(e.RowHandle);
            e.IsEmpty = row.TransferDetails.Count == 0;
        }
        
        private void lueProductCat_EditValueChanged(object sender, EventArgs e)
        {
            var stockinDetail = (StockInDetail)gvStockInDetails.GetRow(gvStockInDetails.FocusedRowHandle);
            if (stockinDetail == null || stockinDetail.PackageUom != null)
            {
                return;
            }
            var lookUpEdit = sender as LookUpEdit;
            if (lookUpEdit == null || lookUpEdit.EditValue == null)
            {
                return;
            }

            var productCategory = _productCategories.FirstOrDefault(t => t.Id == (int) lookUpEdit.EditValue);
            stockinDetail.Product.ProductCategory = productCategory;
        }

        private void gvStockIn_ValidateRow(object sender, ValidateRowEventArgs e)
        {
            var stockInDetail = (StockInDetail) gvStockInDetails.GetRow(gvStockInDetails.FocusedRowHandle);
            // if cannot get current row
            if(stockInDetail == null)
            {
                return;
            }

            gvStockInDetails.ClearColumnErrors();

            if(stockInDetail.Product == null)
            {
                gvStockInDetails.SetColumnError(FormHelper.GetColumn(gvStockInDetails, "Product.Id"),
                                         "Nhập mã hàng");
                e.Valid = false;
            }
            else
            {
                // check for input
                if(string.IsNullOrEmpty(stockInDetail.Product.Code))
                {
                    gvStockInDetails.SetColumnError(FormHelper.GetColumn(gvStockInDetails, "Product.Id"),
                                             "Nhập mã hàng");
                    e.Valid = false;
                }
                else
                {
                    // check for duplicated on editing
                    var existedProductCode = _stockInDetails
                        .Any(t => !Equals(t, stockInDetail) &&
                                  t.Product.Code == stockInDetail.Product.Code);
                    if(existedProductCode)
                    {
                        gvStockInDetails.SetColumnError(FormHelper.GetColumn(gvStockInDetails, "Product.Id"),
                                                 "Mã hàng đã tồn tại trên màn hình");
                        e.Valid = false;
                    }
                    else
                    {
                        // check for duplicated from DB
                        existedProductCode = _session.Products
                            .Any(t => t.Id != stockInDetail.Product.Id &&
                                      t.Code == stockInDetail.Product.Code);
                        if(existedProductCode)
                        {
                            gvStockInDetails.SetColumnError(FormHelper.GetColumn(gvStockInDetails, "Product.Id"),
                                                     "Mã hàng đã tồn tại trong hệ thống");
                            e.Valid = false;
                        }
                    }
                }
            }

            if(stockInDetail.Quantity < 0)
            {
                gvStockInDetails.SetColumnError(FormHelper.GetColumn(gvStockInDetails, "Quantity"),
                                         "Số lượng không hợp lệ");
                e.Valid = false;
            }
        }

        private void gvStockIn_InvalidRowException(object sender, InvalidRowExceptionEventArgs e)
        {
            e.ExceptionMode = DevExpress.XtraEditors.Controls.ExceptionMode.NoAction;
        }
        
    }
}